package net.asrsmid.connection.rs;

import java.net.Authenticator;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Holder;

import net.asrsmid.config.AsRsAuthMode;
import net.asrsmid.config.AsRsAuthenticator;
import net.asrsmid.config.RsApplication;
import net.asrsmid.connection.AsRsPoolableConnection;

import com.microsoft.rs2005.ArrayOfParameterValue;
import com.microsoft.rs2005.ArrayOfString;
import com.microsoft.rs2005.ArrayOfWarning;
import com.microsoft.rs2005.ExecutionHeader;
import com.microsoft.rs2005.ExecutionInfo;
import com.microsoft.rs2005.ParameterValue;
import com.microsoft.rs2005.ReportExecutionService;
import com.microsoft.rs2005.ReportExecutionServiceSoap;
import com.sun.xml.ws.developer.WSBindingProvider;

/**
 * @author Chen WANG
 * @since 05-mai-2011
 */
public class RsWebserviceProxy extends AsRsPoolableConnection {
	private String wsdlUri;
	private String nameSpaceUri;
	private String localPart;
	private String endPointUri;
	private ReportExecutionServiceSoap ress;

	/**
	 * @param config
	 * @throws MalformedURLException
	 */
	public RsWebserviceProxy(RsApplication config) throws MalformedURLException {
		this.wsdlUri = config.getWsdlUri();
		this.nameSpaceUri = config.getNameSpaceUri();
		this.localPart = config.getLocalPart();
		this.endPointUri = config.getEndpointUri();
		
		// authenticator object required for constructing a proxy object
		AsRsAuthMode mode = config.getAuthMode();
		if (mode == AsRsAuthMode.BASIC) {
			String username = config.getDefaultUserName();
			String password = config.getDefaultUserPassword();
			AsRsAuthenticator netAuth = new AsRsAuthenticator(mode, username, password);
			Authenticator.setDefault(netAuth);
		}
		
		URL mrsWsdlUrl = new URL(this.wsdlUri);
		QName mrsQname = new QName(this.nameSpaceUri, this.localPart);
		ReportExecutionService service = new ReportExecutionService(mrsWsdlUrl, mrsQname);

		ress = service.getReportExecutionServiceSoap();
		((BindingProvider) ress).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, this.endPointUri);
	}
	
	/**
	 * @param wsdlUri
	 * @param nameSpaceUri
	 * @param localPart
	 * @param endPointUri
	 * @throws MalformedURLException
	 */
	public RsWebserviceProxy(String wsdlUri, String nameSpaceUri, String localPart, String endPointUri) throws MalformedURLException {
		this.wsdlUri = wsdlUri;
		this.nameSpaceUri = nameSpaceUri;
		this.localPart = localPart;
		this.endPointUri = endPointUri;
		
		URL mrsWsdlUrl = new URL(this.wsdlUri);
		QName mrsQname = new QName(this.nameSpaceUri, this.localPart);
		ReportExecutionService service = new ReportExecutionService(mrsWsdlUrl, mrsQname);

		ress = service.getReportExecutionServiceSoap();
		((BindingProvider) ress).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, this.endPointUri);
	}

	/* (non-Javadoc)
	 * @see net.asrsmid.connection.AsRsPoolableConnection#close()
	 */
	public void release() {
		try {
			pool.returnObject(this);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * @param username
	 * @param password
	 */
	public void setAuthentication(String username, String password) {
		((BindingProvider)ress).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, username);
		((BindingProvider)ress).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password);
	}
	
	/**
	 * 
	 */
	public void resetAuthentication() {
		((BindingProvider)ress).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, null);
		((BindingProvider)ress).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, null);
	}

	/**
	 * 
	 * @param report
	 * @param historyID
	 */
	public ExecutionInfo loadReport(String report, String historyID) {
		return ress.loadReport(report, historyID);
	}

	/**
	 * 
	 * @param execHeader
	 */
	public void setOutboundHeaders(ExecutionHeader execHeader) {
		((WSBindingProvider) ress).setOutboundHeaders(execHeader);
	}

	/**
	 * 
	 * @param reportParamsMap
	 */
	public void setExecutionParameters(Map<String, String> reportParamsMap) {
		if (reportParamsMap != null) {
			Iterator<Entry<String, String>> it = reportParamsMap.entrySet().iterator();
			ArrayOfParameterValue reportParams = new ArrayOfParameterValue();
			while (it.hasNext()) {
				Entry<String, String> entry = it.next();
	
				ParameterValue param = new ParameterValue();
				param.setName(entry.getKey());
				param.setValue(entry.getValue());
	
				reportParams.getParameterValue().add(param);
			}
			ress.setExecutionParameters(reportParams, null);
		}
	}

	/**
	 * 
	 * @param reportFormat
	 * @param deviceInfo
	 * @param result
	 * @param extension
	 * @param mimeType
	 * @param encoding
	 * @param warnings
	 * @param streamIDs
	 */
	public void render(String reportFormat, String deviceInfo, Holder<byte[]> result, Holder<String> extension, Holder<String> mimeType, 
			Holder<String> encoding, Holder<ArrayOfWarning> warnings, Holder<ArrayOfString> streamIDs) {
		ress.render(reportFormat, deviceInfo, result, extension, mimeType, encoding, warnings, streamIDs);
	}

	/**
	 * @return the wsdlUri
	 */
	public String getWsdlUri() {
		return wsdlUri;
	}

	/**
	 * @return the nameSpaceUri
	 */
	public String getNameSpaceUri() {
		return nameSpaceUri;
	}

	/**
	 * @return the localPart
	 */
	public String getLocalPart() {
		return localPart;
	}

	/**
	 * @return the endPointUri
	 */
	public String getEndPointUri() {
		return endPointUri;
	}

	/**
	 * @return the ress
	 */
	public ReportExecutionServiceSoap unwrap() {
		return ress;
	}
}